package sbox

import (
	"io/fs"
	"path/filepath"
	"plugin"

	"gitee.com/dennis-kk/rpc-go-backend/idlrpc"
	"gitee.com/dennis-kk/service-box-go/util/tools"
)

func (sb *ServiceBox) loadAllService() error {
	// load service from waitload pack aage
	for n, p := range sb.waitLoadPack {
		err := sb.loadServiceByPackInfo(p)
		if err != nil {
			sb.logger.Warn("%s load service from package error !", n)
			continue
		}
	}
	sb.waitLoadPack = make(packCache)
	// if config service path, load from directory
	// FIXME read from config
	return sb.loadServiceFromDir("./Debug")
}

func (sb *ServiceBox) loadServiceFromDir(rootPath string) error {
	//check file exist
	if !tools.IsEffectiveDir(rootPath) {
		sb.logger.Warn("no effective shared library storage path")
		return nil
	}

	var bundles []string
	err := filepath.Walk(rootPath, func(path string, info fs.FileInfo, err error) error {
		if err != nil {
			//TODO add error log
			return err
		}
		// skip root path
		if path == rootPath {
			return nil
		}
		//skip dir
		if info.IsDir() {
			return nil
		}
		if filepath.Ext(path) == ".so" {
			bundles = append(bundles, path)
		}
		return nil
	})
	if err != nil {
		//TODO add err log
		return err
	}

	// open dll and get register function
	for _, bundle := range bundles {
		open, err := plugin.Open(bundle)
		if err != nil {
			//TODO add error log
			continue
		}

		varHandle, err := open.Lookup("ServiceUUID")
		if err != nil {
			continue
		}

		funcHandle, err := open.Lookup("Creator")
		if err != nil {
			//TODO add error log
			continue
		}

		//dynamic cast
		if regHandle, ok := funcHandle.(idlrpc.SdkCreateHandle); ok {
			srvUid := varHandle.(uint64)
			srvPack := &idlrpc.PackageInfo{
				ServiceUUID: srvUid,
				Creator:     regHandle,
			}
			err := sb.loadServiceByPackInfo(srvPack)
			if err != nil {
				sb.logger.Warn("%s load service lib error %v", bundle, err)
				continue
			}
			sb.logger.Info("%s load service successful", bundle)
		}

	}
	return nil
}
